package server.data;

import client.ServerOutageThread;
import java.security.*;
import java.text.ParseException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.bouncycastle.util.encoders.Base64;
import security.Base64Coder;
import security.KeyLoader;
import security.exception.KeyLoadingFailedException;
import server.AuctionManager;

/**
 * Represents a Signed Bid
 * @author Group 95
 */
public class SignedBid extends Bid{
    private String user1;
    private long timestamp1;
    private String signature1;
    
    private String user2;
    private long timestamp2;
    private String signature2;
    
    private String firstPart;
    private boolean bFits;
    
    final public static String USAGE="Invalid parameters, Usage: !signedBid <auction-id> <amount> <user1:timestamp1:signature1> <user2:timestamp2:signature2>!";
    final public static String INV_PARAMETERS="Invalid parameters!";
    
    final public static String TIMESTAMP="!timestamp ";

    public SignedBid(final String[] strParts, final User bidder) throws InvalidCommandException
    {
        super(strParts,bidder);
        try
        {
            bFits=false;
            String strSig[]=strParts[3].split(":"); //signature1 in parts

            user1=strSig[0];
            timestamp1=Long.parseLong(strSig[1]);
            signature1=strSig[2];

            strSig=strParts[4].split(":"); //signature2 in parts
            user2=strSig[0];
            timestamp2=Long.parseLong(strSig[1]);
            signature2=strSig[2];
            
            firstPart=TIMESTAMP+strParts[1]+" "+strParts[2];
            try {
                if(checkSignature(firstPart,timestamp1,user1,signature1) && checkSignature(firstPart,timestamp2,user2,signature2))
                {
                    bFits=true;
                }
            } catch (Exception ex) {
                throw new InvalidCommandException("Error checking the sig",ex);
            }
        }
        catch (IndexOutOfBoundsException ex) 
        {
            throw new InvalidCommandException(getErrorMessage(ex),ex);
        }
        catch (NumberFormatException ex) 
        {
            throw new InvalidCommandException(INV_PARAMETERS,ex);
        }
    }
    

    
    /**
     * Checks if the signature is correct
     * @param input
     * @return 
     */
    private boolean checkSignature(String strFirstPart,long timestamp,String username,String strSig) throws Exception {
        String strMessage=strFirstPart+" "+timestamp;
        try {
            byte[] output = null;
            PublicKey key = KeyLoader.loadPublicKey(username);
            try {
                Signature signature = Signature.getInstance("SHA512withRSA");
                signature.initVerify(key);
                signature.update(strMessage.getBytes());
                return signature.verify(Base64.decode(strSig.getBytes()));

            } catch (NoSuchAlgorithmException ex) {
                Logger.getLogger(ServerOutageThread.class.getName()).log(Level.SEVERE, null, ex);
                throw new Exception("Signaturechecking failed", ex);
            } catch (InvalidKeyException ex) {
                Logger.getLogger(ServerOutageThread.class.getName()).log(Level.SEVERE, null, ex);
                throw new Exception("Signaturechecking failed", ex);
            } catch (SignatureException ex) {
                Logger.getLogger(ServerOutageThread.class.getName()).log(Level.SEVERE, null, ex);
                throw new Exception("Signaturechecking failed", ex);
            }
        } catch (KeyLoadingFailedException ex) {
            Logger.getLogger(SignedBid.class.getName()).log(Level.SEVERE, null, ex);
            throw new Exception("Signaturechecking failed", ex);
        }
    }
    
    public long getAverageTimeStamp()
    {
        return (this.timestamp1+this.timestamp1)/2;
    }
    
    public boolean isFitting()
    {
        return this.bFits;
    }
    
    @Override
    protected String getErrorMessage(final Throwable cause)
    {
        String strRet=null;
        if(cause instanceof IndexOutOfBoundsException)
        {
            strRet = USAGE;
        }
        else if((cause instanceof NumberFormatException) || (cause instanceof ParseException))
        {
            strRet = INV_PARAMETERS;
        }
        return strRet;
    }

}
